Resolve DQ04: a Plan's identity is its origin - #2
Merged
Conversation
decision 0017: PlanRef = content hash of the origin (predecessor-less) version. Fully derived (CMP-R10), encodes no location (CMP.DM-R08), cannot collide, and makes 'same Plan' a content fact — two versions share a Plan iff they share an origin, and the origin's own identity is the PlanRef. The required goal becomes the human handle (CMP.DM-R12), so identity need not be readable and stays purely derived — machine identity and human readability each keep their own job. A Plan is never renamed because it was never named. Fixes the real hole: the impl used the catalog directory as the handle, making identity a path (violating CMP.DM-R08); a misfiled version now resolves its Plan from its origin and is rejected on mismatch, not reinterpreted. The CMP-R11 objection (a hash is unavailable before the origin exists) does not bind: authoring references no PlanRef, so starting stays one command. Updates ontology, 01-data-model (CMP.DM-R11/R12), 02-artifacts (dir is the PlanRef), 06-api, 04-cli; DQ04 marked resolved.
Replace the operator-chosen catalog directory name with a derived PlanRef: the content hash of a Plan's origin — the single predecessor-less version. Identity is derived, never chosen, never minted, and encodes no location. - catalog: derive_planref walks predecessor imports to the origin and hashes it; an origin is its own PlanRef (its version-id and the PlanRef are the same hash). load_plan rejects a version whose derived origin != the dir it is filed under, on the same terms as a content-hash-vs-filename mismatch — never reinterpreted. - cli/cmd: start names no plan and scaffolds into a drafts/ staging area with a blank (required) goal; commit derives the PlanRef and files under it — --plan and <plan> args removed. Reads address a Plan by PlanRef (the dir), a unique hash prefix, or, as a nicety, an unambiguous goal. - model: a non-empty goal is required on every version (CMP.DM-R12), checked on the evaluated value so revisions inheriting their goal pass. - display: status and history lead with the goal (the human handle), not the hash. - examples: re-file the three plans under their origin hashes (bytes unchanged); READMEs refer to each plan by its goal and note the PlanRef is the origin hash. - tests: cover origin-files-under-own-hash, revision-shares-PlanRef, misfiled rejection, empty-goal refusal, and goal display; rewrite the e2e + cross-plan suites for the derived-identity, no-name-arg flow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete decision 0017's "goal is the human handle, surfaced wherever a Plan is referenced": the progress and evidence confirmation lines printed the raw PlanRef; show the goal instead (the version is still cited by its hash). Add an acceptance test asserting both commands render the goal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mple The DQ04 edit added CMP.DM-R11/R12 in the Identity section, colliding with the pre-existing Progress/acceptance R11/R12 — a duplicate-id bug that axe vrs check did not catch. Renumber the new pair to R17 (Plan identity) and R18 (goal), leaving the older Progress/Acceptance ids and the 07-evals CMP.DM-R12 citation valid. Update the impl comments that cited the new ids. Also: decision 0017 cited CMP.DM-R08 (Step identity = declared name) as forbidding location-as-identity; the no-location property is the PlanRef ontology entry — corrected. And the 06-api cross-plan example showed a pl_-named dir; under 0017 a plan segment is the origin hash, so the example now uses one and refers to the other plan by its goal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> EOF
The *Ref terms were coined for the minted-reference design, where identities were opaque tokens you passed around. That design is gone: a Step's identity is its declared export name (0012) and a Plan's is its origin hash (0017) — intrinsic identities, not reference tokens. - StepRef is dropped as a standalone term. There is no ref artifact: a Step's identity is its name, and depending on a Step names the declaration (a language reference). Folded into the Step ontology entry. - PlanRef -> PlanId: it is an identity (a derived hash), not a pointer to elsewhere; a cross-Plan reference imports the other version. Propagated across the current layer (specs, api, cli, examples, code incl. derive_planref -> derive_planid). The superseded decision 0004 keeps the old terms as a historical record; the ontology's _Avoid_ lists PlanRef/StepRef so a reader of old records maps them. 130 lib + 15 acceptance, clippy/fmt/vrs green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> EOF
The 22-term list was flat. Group under six headings so the structure is legible without reading every entry: the tool; intent (Plan, PlanId, Version, Revision, Rationale, Step); lineage and its states (Head, Divergence, Reconciliation, Orphan, Unresolved); reading, storage, and replication; execution record; change surface and composition. Term text unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…name predecessor→parent Interview-resolved ontology-refinement pass: - Surface cluster: drop Plan Surface, Receipt, Observation as terms. Anchor on Commit as the single write act; the write surface has two acts (Commit → Plan Version, Progress Event → append), not one Mutation umbrella. The Plan Surface invariant survives as a property; Receipt's role is the version hash itself; Observation's guarantee relocates to 05-integrations. - Add Goal, Acceptance, Evidence as terms. Strike phantom Gate — the acceptance predicate is the gate. - Rename predecessor → parent (aligns with the `parents` the impl already emits). - Split lineage terms: "Lineage shapes" (Head, Divergence, Reconciliation) vs "Incomplete replication" (Orphan, Unresolved). - Rationale keeps its term, bridged explicitly to the `why` field. Mutation→Commit and Receipt→Plan Version propagated across specs/requirements and the governing 0001 decision; CMP.SURF-R03 rescoped to the two-act model. Decisions and frozen example modules keep their period vocabulary. axe vrs check --profile strict: ok Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rename predecessor → parent across src and tests (helper fns, error strings, doc-comments, test names). The JSON already emitted `parents`; this closes the gap between the code's internal words and what it produces. - Rename receipt_json → commit_result_json: the output has no `receipt` key, and the ontology no longer defines Receipt — the returned value is the Plan Version. - Rewrite the readiness "On gates" note: the spec no longer says "dependencies and gates"; the ontology states the acceptance predicate *is* the gate. Frozen example modules under catalog/plans/*/versions/*.ts are untouched — they keep their period vocabulary, and the acceptance hash oracle (example_filenames_reproduce_from_source_bytes) confirms none drifted. cargo test: 15 passed. clippy + fmt clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
schickling
marked this pull request as ready for review
July 27, 2026 14:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves DQ04 — a Plan's identity, now that minting is gone and it cannot be the path.
Decision (0017)
A Plan's identity (PlanRef) is the content hash of its origin — the one version with no predecessor. Fully derived, encodes no location, collision-free; two versions are the same Plan iff they share an origin, and the origin's own hash is the PlanRef. The required
goalis promoted to the human handle, so identity stays purely machine-facing and never has to be readable.This fixes a real hole: the implementation used the catalog directory as the Plan's handle, making identity a filesystem location (which the PlanRef ontology entry forbids) — so a moved or misfiled version silently changed which Plan it belonged to.
What changed
derive_planref: an origin is its own PlanRef; a revision walks its predecessor imports to the origin and hashes that. The operator names nothing.starttakes no identifier (only--goal), scaffolds into adrafts/staging area;commitderives the PlanRef and files underplans/<planref>/.goalis required (validated on the evaluated value) and is surfaced bystatus/show/history/progress/evidencein place of the hash; reads resolve a Plan by PlanRef, unique hash-prefix, or unique goal.git mv— version bytes and filenames unchanged, so the filename-reproduces-from-bytes oracle holds; READMEs refer to each plan by its goal.Verification
cargo build --release,clippy --all-targets -- -D warnings,fmt --checkclean;cargo test130 lib + 15 acceptance;nix build .#compasspasses;axe vrs check --profile strictgreen.Also in this PR
CMP.DM-R11/R12collided with the Progress/acceptance block) by renumbering the new pair toR17/R18. Note:axe vrs checkdid not catch the duplicate ids — a checker gap, flagged separately.CMP.DM-R08mis-citation and the stalepl_-named cross-plan example.Known, out of scope
pl_*dirs would have every plan rejected-as-misfiled. Correct per 0017; acceptable at v0 (no users), no migration path provided (fresh-namespace).Draft for review of the identity model before it lands on
main.Also: identity vocabulary cleanup (revisiting the ontology)
The
*Refterms were coined for the minted-reference design (opaque tokens). That design is gone — a Step's identity is its declared name (0012), a Plan's is its origin hash (0017). So:Stepontology entry.Propagated across specs/api/cli/examples/code (
derive_planref→derive_planid); the superseded decision 0004 keeps the old terms as a historical record, and the ontology_Avoid_lists them so old records map cleanly.